home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1998 November: Tool Chest / Dev.CD Nov 98 TC.toast / What's New? / Development Kits / USBDDK_v1.0.1_updated / Examples / USBSampleStorageDriver / StorageClassShim.c < prev    next >
Encoding:
C/C++ Source or Header  |  1998-09-29  |  9.4 KB  |  362 lines  |  [TEXT/MPS ]

  1. /*
  2.     File:        StorageClassShim.c
  3.  
  4.     Contains:    USB Storage Class Shim
  5.  
  6.     Version:    1.0
  7.  
  8.     Copyright:    © 1998 by Apple Computer, Inc., all rights reserved.
  9.  
  10. */
  11.  
  12. #include <Types.h>
  13. #include <Devices.h>
  14. #include <processes.h>
  15. #include <CodeFragments.h>
  16. #include <Resources.h>
  17. #include <DriverServices.h>
  18. #include <Folders.h>
  19. #include <USB.h>
  20.  
  21. #include "StorageClassShim.h"
  22. #include "SampleStorageVersion.h"
  23. #include "SampleStorageDeviceID.h"
  24.  
  25. // Enumerations for the range of Unittable entries
  26. // in which InstallDriverFromMemory will try to install the driver
  27. enum
  28. {
  29.     kUnitTableEntryStart    = 48,
  30.     kUnitTableEntryEnd        = 127
  31. };
  32.  
  33. // These are the structures and definitions used for the Refnum Association array.
  34. // This array handles associating USBDeviceRefs with UnitTable Driver refnums, so
  35. // Drivers can be removed from the UnitTable when the drive is removed.
  36. enum
  37. {
  38.     kMaxNumberOfDrives = 50
  39. };
  40.  
  41. struct RefnumAssociation
  42. {
  43.     USBDeviceRef     theDevRef;
  44.     DriverRefNum    drvrRefNum;
  45. };
  46.  
  47. typedef struct RefnumAssociation    RefnumAssociation;
  48.  
  49.  
  50. // These are all variables that are global to the Shim
  51. static RefnumAssociation    theRefAssoc[kMaxNumberOfDrives];
  52. static Boolean                 shimInFile;
  53. static FSSpec                shimFSSpec;
  54. static TimerID                gGiveTimeTimer = nil;
  55. static DriverRefNum            gNewDrvrRef = 0;
  56.  
  57. static OSStatus GiveTimeSecondaryInterrupt( void *p1, void *p2);
  58.  
  59. unsigned char USBShim(void)
  60. {
  61.     OSStatus status = noErr;
  62.     USBDeviceNotificationParameterBlock pb;
  63.  
  64.     // Clear out the Association array
  65.     BlockZero((Ptr) theRefAssoc, sizeof(RefnumAssociation) * kMaxNumberOfDrives);
  66.  
  67.     // Setup notification for Vendor Specific Devices
  68.     pb.usbDeviceNotification = -1;            // tell me about everything
  69.     pb.usbClass = -1;    // tell me about vendor specific
  70.     pb.usbSubClass = -1;
  71.     pb.usbProtocol = -1;
  72.     pb.usbVendor = kDriverVendorID;                // Only notify me for the shuttle cable
  73.     pb.usbProduct = kDriverProductID;            // allow any product ID to notify us
  74.     pb.result = noErr;
  75.     pb.callback = (USBDeviceNotificationCallbackProcPtr) &myNotificationCallback;        
  76.     pb.refcon = nil;
  77.      USBInstallDeviceNotification (&pb);    
  78.  
  79.     return 0;
  80. }
  81.  
  82. static Boolean gControlCallIsDone = false;
  83.  
  84. void ControlComplete( ParmBlkPtr paramBlock )
  85. {
  86. #pragma unused (paramBlock)
  87.  
  88.     gControlCallIsDone = true;
  89. }
  90.  
  91. OSStatus ShimOpenDriver(USBDeviceRef theDevRef)
  92. {
  93.     OSStatus            theErr = noErr;
  94.     Handle                hDrvrResource;
  95.     short                loopCount;
  96.     THz                    currentZone;
  97.     
  98.     // We have been notified of a new device, check to see if we already 
  99.     // have installed a driver the USB Device Ref.
  100.     for( loopCount = 0; loopCount < kMaxNumberOfDrives; loopCount++)
  101.     {
  102.         if(theDevRef == theRefAssoc[loopCount].theDevRef)
  103.         {
  104.             // Driver has already been installed for this USBDeviceRef,
  105.             // Nothing else needs to be done, report back noErr to the notifier
  106.             return noErr;
  107.         }
  108.     }
  109.  
  110.     // No driver has been loaded for this USBDeviceRef, find the driver's 'ndrv' resource        
  111.     if (shimInFile)
  112.     {
  113.         short    oldResFileID = 0, 
  114.                 myResFileID = 0;
  115.  
  116.         SetResLoad(true);
  117.         oldResFileID = CurResFile();                                    // get the current resource file ID
  118.         myResFileID = FSpOpenResFile(&shimFSSpec, fsRdPerm);
  119.         UseResFile(myResFileID);                                        // point at the shim file
  120.  
  121.         currentZone = GetZone ();
  122.         SetZone ( SystemZone() );
  123.         hDrvrResource = GetResource('ndrv', 128);                        // read in the driver from a ndrv resource
  124.         DetachResource(hDrvrResource);                                    // Detach the resource so it hangs around in the system heap
  125.         SetZone (currentZone);
  126.  
  127.         UseResFile(oldResFileID);                                        // point at the original file
  128.         CloseResFile(myResFileID);                                        // Make sure the resource file is closed
  129.     }
  130.     else
  131.     {
  132.         hDrvrResource = GetResource('ndrv', 128);                        // read in the driver from a ndrv resource
  133.     }
  134.     
  135.     // We have found the driver's 'ndrv' resource, install it into the UnitTable
  136.     if (hDrvrResource)
  137.     {
  138.         long                drvrSize;
  139.         Ptr                    pDrvrInMemory;
  140.         DriverRefNum        drvrRefNum;
  141.         void                *pTheStorageClassDispatchTable;
  142.         CFragSymbolClass    symClass;
  143.         CFragConnectionID    connID;
  144.         short                loopCount;
  145.  
  146.         // Lock the Driver Resource in memory
  147.         HLock(hDrvrResource);
  148.  
  149.         // Get the resource information needed to install the Driver
  150.         pDrvrInMemory = *hDrvrResource;
  151.         drvrSize = GetHandleSize(hDrvrResource);
  152.  
  153.         // Install the driver
  154.         theErr = InstallDriverFromMemory(pDrvrInMemory, drvrSize, nil, (RegEntryIDPtr) nil, kUnitTableEntryStart, kUnitTableEntryEnd, &drvrRefNum);
  155.         if ( theErr != noErr )
  156.         {
  157.             // The driver could not be loaded, the shim will return the error and abort the driver load
  158.             return theErr;
  159.         }
  160.  
  161.         gNewDrvrRef = drvrRefNum;
  162.         
  163.         // Save the Driver refnum to remove the driver when the remove notification is recieved
  164.         for( loopCount = 0; loopCount < kMaxNumberOfDrives; loopCount++ )
  165.         {
  166.             if (( theRefAssoc[loopCount].theDevRef == 0 ) && (theRefAssoc[loopCount].drvrRefNum == 0) )
  167.             {
  168.                 theRefAssoc[loopCount].theDevRef = theDevRef;
  169.                 theRefAssoc[loopCount].drvrRefNum = drvrRefNum;
  170.                 break;
  171.             }
  172.         }
  173.  
  174.         // If the array is already full, this drive will not be added to the array.  This means that the Shim will never
  175.         // remove the driver it the drive is detached.  This will only happen if more than kMaxNumberOfDrives are attached
  176.         // at any one time.
  177.  
  178.         // Get the Storage class dispatch table 
  179.         USBGetDriverConnectionID(&theDevRef, &connID);
  180.         currentZone = GetZone ();
  181.         SetZone ( SystemZone() );
  182.         
  183.         theErr = FindSymbol(connID, "\pTheStorageClassDispatchTable", (Ptr *)&pTheStorageClassDispatchTable, &symClass);
  184.         SetZone (currentZone);
  185.  
  186.         // If no error occured, pass the dispatch table pointer to the Driver
  187.         if (theErr == noErr)            
  188.         {
  189.             CntrlParam    cntrlPB;
  190.             
  191.             cntrlPB.ioCompletion = NewIOCompletionProc( &ControlComplete );
  192.             cntrlPB.ioVRefNum = 0;
  193.             cntrlPB.ioCRefNum = drvrRefNum;
  194.             cntrlPB.csCode = 500; // currently the code for set dispatch table;
  195.             *((UInt32 *) &cntrlPB.csParam[0]) = (UInt32) pTheStorageClassDispatchTable;
  196.  
  197.             gControlCallIsDone = false;
  198.  
  199.             theErr = PBControlAsync((ParmBlkPtr) &cntrlPB );
  200.             if(theErr == noErr)
  201.             {
  202.  
  203.                 // Wait for the control call to complete
  204.                 // Loop doing nothing until call is done
  205.                 while (gControlCallIsDone == false);
  206.             }
  207.         }
  208.         
  209.         if ( theErr != noErr )
  210.         {
  211.             // if an error occurs, we should remove the driver from the unittable
  212.         }
  213.     }
  214.     
  215.     return theErr;
  216. }
  217.  
  218. OSStatus ShimCloseDriver(USBDeviceRef theDevRef)
  219. {
  220.     OSStatus            theErr = noErr;
  221.     short                loopCount;
  222.  
  223.     for( loopCount = 0; loopCount < kMaxNumberOfDrives; loopCount++)
  224.     {
  225.         if(theDevRef == theRefAssoc[loopCount].theDevRef)
  226.         {
  227.             if(theRefAssoc[loopCount].drvrRefNum != 0)
  228.             {
  229.                 VCBPtr vol;
  230.                 
  231.                 vol = (VCBPtr) (GetVCBQHdr())->qHead;
  232.                 
  233.                 while (vol)
  234.                 {
  235.                     // Check to see if this volume belongs to the driver
  236.                     // that is being removed
  237.                     if( vol->vcbDRefNum == theRefAssoc[loopCount].drvrRefNum)
  238.                     {
  239.                         IOParam     offlinePB;
  240.                         OSErr        err;
  241.                         
  242.                         BlockZero(&offlinePB, sizeof(IOParam));
  243.                         offlinePB.ioCompletion = nil;    
  244.                         offlinePB.ioResult = noErr;    
  245.                         offlinePB.ioNamePtr = nil;    
  246.                         offlinePB.ioVRefNum = vol->vcbVRefNum;    
  247.                         
  248.                         //err = PBOffLine((ParamBlockRec *) &offlinePB);
  249.                         err = PBUnmountVol((ParamBlockRec *) &offlinePB);
  250.                         if(err == fBsyErr)
  251.                         {
  252.                             err = PBEject((ParamBlockRec *) &offlinePB);
  253.                             gNewDrvrRef = 0;
  254.                         }
  255.                     }
  256.                     
  257.                     vol = (VCBPtr) vol->qLink;
  258.                 }
  259.                 
  260.                 theErr = RemoveDriver(theRefAssoc[loopCount].drvrRefNum, false);
  261.                 theRefAssoc[loopCount].theDevRef = 0;
  262.                 theRefAssoc[loopCount].drvrRefNum = 0;
  263.                 
  264.                 if(gNewDrvrRef == 0)
  265.                 {
  266.                     OSStatus             status;
  267.                     AbsoluteTime        theWait;
  268.                 
  269.                     theWait = DurationToAbsolute(durationSecond);
  270.                     theWait = AddAbsoluteToAbsolute(UpTime(), theWait);
  271.                     status = SetInterruptTimer( &theWait, &GiveTimeSecondaryInterrupt, nil, &gGiveTimeTimer);
  272.                 }
  273.             }
  274.             
  275.             return theErr;
  276.         }
  277.     }
  278.     
  279.     return theErr;
  280. }
  281.  
  282. OSStatus GiveTimeSecondaryInterrupt( void *p1, void *p2)
  283. {
  284. #pragma unused ( p1, p2 )
  285.     Boolean     DrvrVolumeFound = false;
  286.  
  287.     gGiveTimeTimer = nil;
  288.  
  289.     if(gNewDrvrRef != 0)
  290.     {
  291.         VCBPtr vol;
  292.         
  293.         vol = (VCBPtr) (GetVCBQHdr())->qHead;
  294.         
  295.         while (vol)
  296.         {
  297.             // Check to see if this volume belongs to the driver
  298.             // that is being removed
  299.             if( vol->vcbDRefNum == gNewDrvrRef)
  300.             {
  301.                 DrvrVolumeFound = true;
  302.                 break;
  303.             }
  304.             
  305.             vol = (VCBPtr) vol->qLink;
  306.         }
  307.     }
  308.  
  309.     if( DrvrVolumeFound == false )
  310.     {
  311.         OSStatus             status;
  312.         AbsoluteTime        theWait;
  313.  
  314.         SystemTask();
  315.         theWait = DurationToAbsolute(durationSecond);
  316.         theWait = AddAbsoluteToAbsolute(UpTime(), theWait);
  317.         status = SetInterruptTimer( &theWait, &GiveTimeSecondaryInterrupt, nil, &gGiveTimeTimer);
  318.     }
  319.                 
  320.     return noErr;
  321. }
  322.  
  323. void myNotificationCallback(USBDeviceNotificationParameterBlock *pb)
  324. {
  325.     switch(pb->usbDeviceNotification)        // why were we notified?
  326.     {
  327.         case kNotifyAddDevice:                // because mass storage device appeared
  328.         case kNotifyAddInterface:            // because mass storage interface appeared
  329.         {    
  330.             ShimOpenDriver(pb->usbDeviceRef); 
  331.         }
  332.         break;
  333.             
  334.         case kNotifyRemoveDevice:            // because a mass storage device or interface disappeared
  335.         case kNotifyRemoveInterface:        // because a mass storage device or interface disappeared
  336.         {
  337.             ShimCloseDriver(pb->usbDeviceRef);
  338.         }
  339.         break;
  340.             
  341.         default:
  342.             break;
  343.     }
  344. }
  345.  
  346. void USBShimTermination(void)
  347. {
  348.     // put back the original vectors
  349. }
  350.  
  351. OSErr CFragInitRoutine(CFragInitBlockPtr initBlkPtr)
  352. {
  353.     shimInFile = false;
  354.     
  355.     if (CFragHasFileLocation(initBlkPtr->fragLocator.where))
  356.     {
  357.         shimInFile = true;
  358.         shimFSSpec = *(initBlkPtr->fragLocator.u.onDisk.fileSpec);            // save the FSSpec, in case we need it later
  359.     }
  360.     return noErr;
  361. }
  362.